﻿package com.saint.bitmapDistortion 
{
	import com.saint.elasticity.ElasticObject;
	import com.saint.elasticity.FixedAnchorPoint;
	import com.saint.elasticity.IAnchorPoint;
	import com.saint.utils.Logger;
	import com.saint.utils.TileMaker;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import org.flashsandy.display.DistortImage;
	/**
	 * 
	 * take in a disaply image and make it stretchable
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * @author kembera
	 */
	public class StretchyElasticImage extends Sprite
	{
		
		private var shape:Shape = new Shape();
		private var showGrid:Boolean = false;
		private var buttonAlpha:Number = 0.0;
		private var _cols:uint;
		private var _rows:uint;
		private var _tileH:Number;
		private var _tileW:Number;
		private var _buttons:Array = new Array();
		private var stretchyTiles:Array = new Array();
		private var bitmapTiles:Array = new Array(); //not Needed !!?
		private var bitmapDataTiles:Array  = new Array();
		private var resetPositions:Array = new Array();
		
		private var scope:Sprite;
		
		
		/**
		 * CONSTRUCTOR
		 * 
		 * creates a stretchy image out of the supplied display object, splitting it into the desirec number of row and columns
		 * 
		 * @param	srcDisplayObject
		 * @param	cols
		 * @param	rows
		 */
		public function StretchyElasticImage(srcDisplayObject:DisplayObject, cols:uint = 3, rows:uint= 3)
		{
			Logger.info("StretchyImage.StretchyImage " + srcDisplayObject + ", " + cols + ", " + cols);
			
			scope = this;
			/* set number of rows and columns and calculate tile width and height */
			_cols = cols;
			_rows = rows;
			
			_tileW = srcDisplayObject.width / _cols;
			_tileH = srcDisplayObject.height / _rows;	
			
			/* split the image into tiles and store as array of bitmapData*/	
			bitmapDataTiles= TileMaker.makeTiles(srcDisplayObject, _cols, _rows);
		}
		
		
		/**
		 * INIT 
		 */
		public function init():void
		{			
			Logger.debug("StretchyImage.StretchyImage bitmapData tiles made: " + bitmapDataTiles.length);
			
			/* create an array of bitmaps */
			for (var i:Number = 0; i < bitmapDataTiles.length; i++)
			{
				bitmapTiles.push(new Bitmap(bitmapDataTiles[i]));
			}
			
			/* create an array to hold the stretychImage tiles */
			var width:Number;
			var height:Number;
			for (var n:Number = 0; n <bitmapTiles.length; n++)
			{
				width = Bitmap(bitmapTiles[n]).width;
				height = Bitmap(bitmapTiles[n]).height;
				var distortionTile:DistortImage = new DistortImage(width, height, 1, 1);
				stretchyTiles.push(distortionTile);
			}
			
			
			/* create the buttons */
			createButtons();
			
			layoutButtons();
			
			Logger.debug("StretchyImage.StretchyImage: _buttons.length: " + _buttons.length); 
			
			/* add the holding shape to the stage */
			this.addChild(shape);			
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			
			//onEnterFrame(null);
		}
		
		
		/**
		 * ENTER FRAME FUNCTION
		 * 
		 * tells each stretch tile is it's corners
		 * 	
		 * @param	e
		 */
		private function onEnterFrame(e:Event):void 
		{
			/* clear the last frames bitmaps */
			this.shape.graphics.clear();
			this.setChildIndex(shape, 0);
			//this.shape.alpha = 0.2;			
			
			/* show the triagle grid */
			if (this.showGrid){
				this.shape.graphics.lineStyle(1, 0xffcc00);
			}			
			
			/* variables to hold the display object to anchor the stretchy tile to */
			var topLeft:DisplayObject;
			var topRight:DisplayObject;
			var bottomLeft:DisplayObject;
			var bottomRight:DisplayObject;
			
			/* variable to hold the array index number of the 'button' in _buttons' */
			var topLeftNum:Number ; 
			var bottomLeftNum: Number ;
			var topRightNum:Number ;					
			var bottomRightNum:Number ;
				
			Logger.debug("\n--------------------------------");
			Logger.debug("--------------------------------");
			for (var p:Number = 0 ; p < _buttons.length; p++)
			{
				
				if (_buttons[p].type == "EO")
				{
					Logger.debug("StretchyElasticImage.EnterFrame for button: " + p);
					ElasticObject(_buttons[p]).enterFrameEvents(null);
				}
				
			}			
			
			Logger.debug("--------------------------------");
			
			
			
			for (var i:Number = 0; i < _rows; i++)
			{			
				for (var n:Number = 0; n < _cols; n++)
				{			
					var col:Number = n;
					var row:Number = i;
					
					var index:Number = n + (i * (_cols));
					
					topLeftNum= ((_cols+1) * i ) + n
					bottomLeftNum= ((_cols+1) * i) + (_cols + 1) + n;
					topRightNum= topLeftNum + 1;					
					bottomRightNum=  bottomLeftNum + 1;
					
					
					
					topLeft = _buttons[topLeftNum];
					bottomLeft = _buttons[bottomLeftNum];
					topRight = _buttons[topRightNum];
					bottomRight = _buttons[bottomRightNum];
					
					//if (i == 0 && n == 0)
					//{
						trace("");
						Logger.debug("tile"+index + ":  " + n + " ," + i + " ,topLeftNum: " + topLeftNum +  " ,topRightNum: " + topRightNum + " ,bottomRightNum: " + bottomRightNum  +  " ,bottomLeftNum: " +  bottomLeftNum );
						Logger.debug("tile"+index + ":  " + n + " ," + i + " ,topLeft.name: " + topLeft.name +  " ,topRight.name: " + topRight.name+ " ,bottomRight.name: " + bottomRight.name  +  " ,bottomLeft.name: " +  bottomLeft.name );
						//Logger.debug("\t" + n + " ," + i + " ,\n\ttopLeftNum: " + getDisplayObjectCenter(topLeft, 0, 0) +  " ,\n\ttopRightNum: " + getDisplayObjectCenter(topRight, 0, 0) + " ,\n\tbottomRightNum: " + getDisplayObjectCenter(bottomRight,0,0)  +  " ,\n\tbottomLeftNum: " +  getDisplayObjectCenter(bottomLeft,0,0) );
					//}
				 
					
						DistortImage(stretchyTiles[i]).setTransform(this.shape.graphics, 
																	BitmapData(this.bitmapDataTiles[index]),
																	new Point(topLeft.x, topLeft.y),
																	new Point(topRight.x, topRight.y),
																	new Point(bottomRight.x, bottomRight.y),
																	new Point(bottomLeft.x, bottomLeft.y));
					
					
					
					
					//DistortImage(stretchyTiles[i]).setTransform(this.shape.graphics, 
																	//BitmapData(this.bitmapDataTiles[index]),
																	//this.getDisplayObjectCenter(topLeft, 0, 0),
																	//this.getDisplayObjectCenter(topRight, 0, 0),
																	//this.getDisplayObjectCenter(bottomRight, 0, 0),
																	//this.getDisplayObjectCenter(bottomLeft, 0, 0));
																	
				}
			}
				
			
			/*distortion1.setTransform(this.shape.graphics, 
						this.bitmap1.bitmapData, 
						this.getDisplayObjectCenter(this.dragBtn1, -50, -50), 
						this.getDisplayObjectCenter(this.dragBtn2, -50, -50), 
						this.getDisplayObjectCenter(this.dragBtn3, -50, -50), 
						this.getDisplayObjectCenter(this.dragBtn4, -50, -50));*/
		}
		
	/**
		 * lays out the buttons on the scope
		 * 
		 * 	0	-	1	-	2	-	3	-	4
		 * 
		 * 	5	-	6	-	7	-	9	-	10
		 * 
		 * 	1	-	12	-	13	-	14	-	15
		 * 
		 * 
		 */
		private function layoutButtons():void
		{
			Logger.info("StretchyImage.layoutButtons");
			
			var leftBut:IAnchorPoint;
			var rightBut:IAnchorPoint;
			var topBut:IAnchorPoint;
			var bottomBut:IAnchorPoint;
			var currentElasticObj:ElasticObject;
			var index:Number;
			var pnt:Point;
			
			for (var i:Number = 0; i <= _rows; i++)
			{
				for (var n:Number = 0; n <= _cols; n++)
				{
					index = n + (i * (_cols + 1));
					pnt = new Point(n * _tileW,i * _tileH)
					_buttons[index].x = pnt.x;  
					_buttons[index].y = pnt.y;  
				//	_buttons[index].label(String(index));
					_buttons[index].alpha = buttonAlpha; 
					resetPositions.push(pnt);
					scope.addChild(_buttons[index]);	
					
					/* set the top row */
					if (i == 0)
					{
						/* topLeftCorner */
						if (n == 0) { Logger.debug(n + ", " + i + " : top left") }
						else
						
						/* topRight */
						if (n == _cols) { Logger.debug(n + ", " + i + " : top right") }
						
						else						
						{
							/* top row */
							Logger.debug(n + ", " + i + " : top row elastic objects")				
							currentElasticObj = _buttons[index];
							leftBut = _buttons[index - 1];
							rightBut = _buttons[index + 1];							
							currentElasticObj.attachSpringFrom(leftBut);
							currentElasticObj.attachSpringFrom(rightBut);
							currentElasticObj.init();						
						};
					}
					else
					/* set the bottom row */
					if (i == _rows )
					{
						/* bottomLeftCorner */
						if (n == 0) { Logger.debug(n + ", " + i + " : bottom left") }
						
						else
						
						/* bottmoRight */
						if (n == _cols) { Logger.debug(n + ", " + i + " : bottom right") }
						
						else						
						{							
							Logger.debug(n + ", " + i + " : bottom row");				
							currentElasticObj = _buttons[index];
							leftBut = _buttons[index - 1];
							rightBut = _buttons[index + 1];							
							currentElasticObj.attachSpringFrom(leftBut);
							currentElasticObj.attachSpringFrom(rightBut);
							currentElasticObj.init();	
						};
					}
					else
					/* set the left sides */
					if (n == 0)
					{
						Logger.debug(n + ", " + i + " : left side");
						currentElasticObj = _buttons[index];
						topBut = _buttons[index - (_cols+1)];
						bottomBut = _buttons[index + (_cols+1)];							
						currentElasticObj.attachSpringFrom(topBut);
						currentElasticObj.attachSpringFrom(bottomBut);
						currentElasticObj.init();	
						
					}
					else
					/* set the right sides */
					if (n == _cols )
					{
						Logger.debug(n + ", " + i + " : right side") ;
						currentElasticObj = _buttons[index];
						topBut = _buttons[index - (_cols+1)];
						bottomBut = _buttons[index + (_cols+1)];							
						currentElasticObj.attachSpringFrom(topBut);
						currentElasticObj.attachSpringFrom(bottomBut);
						currentElasticObj.init();	
					}
					/* set the interior ponts */
					else
					{
						Logger.debug(n + ", " + i + " : interior") ;			
						currentElasticObj = _buttons[index];
						topBut = _buttons[index - (_cols+1)];
						bottomBut = _buttons[index + (_cols+1)];
						leftBut = _buttons[index - 1];
						rightBut = _buttons[index + 1];	
						
						
						currentElasticObj.attachSpringFrom(leftBut);
						currentElasticObj.attachSpringFrom(rightBut);							
						currentElasticObj.attachSpringFrom(topBut);
						currentElasticObj.attachSpringFrom(bottomBut);
						currentElasticObj.init();				
					}
					
					
					
					
					
				}
			}
			
		}
		
		
		
		/**
		 * 
			create anchor points for the corners and elastic points for the rest of the gubbins
		
		 * @param	_rows
		 * @param	_cols
		 */
		private function createButtons():void
		{
	
			Logger.info("ElasticityTest.createElasticGrid");
			
			var dragBtn:IAnchorPoint;
			for (var i:Number = 0; i < (_cols + 1) * (_rows + 1); i++)
			{			
				/* get the left side outer buttons == 0*/
				if (i % (_cols + 1) == 0)
				{
					if (i == 0 )
					{
						/* top left corner */
						dragBtn = new FixedAnchorPoint();
					}else if ( i == (_cols + 1) * _rows) {
						/* bottom left corner */
						dragBtn = new FixedAnchorPoint();						
					}else {
						/* left side */
						dragBtn = new ElasticObject();
					}
				}else 			
				/* get the right side buttons  == _cols*/
				if ((i % (_cols + 1) == _cols))
				{					
					if (i == _cols  )
					{					
						/* top right corner */
						dragBtn = new FixedAnchorPoint();
					}else if (i == _cols + (_cols + 1) * _rows) {		
						/* bottom left corner */
						dragBtn = new FixedAnchorPoint();
					}else{
						/* right side */	
						dragBtn = new ElasticObject();
					}
				}
				else {
					/* middle bits */
					dragBtn = new ElasticObject();
				}
							
			
				// make new IAnchorpiont				
				_buttons.push(dragBtn);
				
			}
			
			layoutButtons();
		
		}
		
		//TODO - look at what x and y are needed for
		private function getDisplayObjectCenter (child:DisplayObject, x:Number=0, y:Number=0):Point {
			var center:Point = new Point();
			center.x = child.x + child.width/2 + x;
			center.y = child.y + child.height/2 + y;
			return center;
		}
		
		
		
		
		/**
		 * stop button drag
		 * @param	e
		 */
		private function stopButtonDrag(e:MouseEvent):void 
		{
			e.target.stopDrag();
		}
		
		/**
		 * start button brag
		 * @param	e
		 */
		private function startButtonDrag(e:MouseEvent):void 
		{
			e.target.startDrag(false);
		}
		
		public function reset():void
		{
			for (var i:Number = 0 ; i <  _buttons.length;i++ )
			{
				_buttons[i].x = resetPositions[i].x;
				_buttons[i].y = resetPositions[i].y;
			}
		}
		
		public function get cols():uint { return _cols; }
		
		public function get rows():uint { return _rows; }
		
		public function get buttons():Array { return _buttons; }
		
	}

}